package com.mh.web.controller;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.validation.ConstraintViolation;
import javax.validation.Validator;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.mh.domain.Customer;
import com.mh.domain.Invoice;
import com.mh.domain.Item;
import com.mh.domain.Product;
import com.mh.service.CustomerService;
import com.mh.service.InvoiceService;
import com.mh.service.ItemService;
import com.mh.service.ProductService;
import com.mh.web.utils.CustomGenericResponse;
import com.mh.web.utils.Page;

@Controller
@RequestMapping(value = "/invoices")
public class InvoiceController {

	@Autowired
	private InvoiceService invoiceService;
	
	@Autowired
	private CustomerService customerService;
	
	@Autowired
	private ItemService itemService;
	
	@Autowired
	private ProductService productService;

	private Validator validator;

	@Autowired
	public InvoiceController(Validator validator) {
		this.validator = validator;
	}
	
	@RequestMapping(method = RequestMethod.GET)
	public String getPage(HttpSession session){
		setProductList(session);
		return "invoices";
	}
	
	private Customer getSesCustomer(HttpSession session){
		return(Customer)session.getAttribute("customer");	
	}
	
	/*master invoice methods*/
	
	
	@RequestMapping(value = "/list", method = RequestMethod.GET)
	public @ResponseBody Page<Invoice> listUsers(Invoice invoice,HttpSession session,
			@RequestParam(value = "page", required = false, defaultValue = "1") int page,
		      @RequestParam(value = "max", required = false, defaultValue = "20") int max){
		
		Customer customer = getSesCustomer(session);
		
		
		List<Invoice> lst = invoiceService.findAllInvoicesForCustomer(customer, page, max);
		Page<Invoice> pg = new Page<Invoice>();
		pg.setMax(max);
		pg.setPage(page);
		pg.setRows(lst);
		return pg;
	}
	
	@RequestMapping(value = "/save", method = RequestMethod.PUT)	
	public @ResponseBody CustomGenericResponse  save(
			@RequestBody Invoice invoice, HttpSession session){
		CustomGenericResponse resp = new CustomGenericResponse();

		Customer cust =  getSesCustomer(session);
		invoice.setCustomer(cust);
		invoice.setCreatedBy(getUserName());
		invoice.setCreatedOn(new java.util.Date());
		
		List<String> errors = validate(invoice);
		
		
		
		
		if(!errors.isEmpty()){
			resp.setSuccess(false);			
			resp.setMessages(errors);
			return resp;
		}
		
		try {
			invoiceService.saveInvoice(invoice);		
		} catch (Exception e) {
			if(e.getMessage().indexOf("MHTEST.AK_INVOICE") == -1){
				errors.add("El numero de factura ingresado ya existe ["+ invoice.getDocument() + "]");
				return resp;
			}else{
				errors.add("Error al agregar Factura "+e.getMessage() );
			}			
		}
		
		
		return resp;
	}
	
	@RequestMapping(value = "/update/{id}", method = RequestMethod.PUT)
	public @ResponseBody CustomGenericResponse  update(
			@RequestBody Invoice invoice, @PathVariable("id") int id, HttpSession session){
		CustomGenericResponse resp = new CustomGenericResponse();

		Customer cust =  getSesCustomer(session);;
		invoice.setCustomer(cust);
		
		
		invoice.setModifiedBy(getUserName());
		invoice.setModifiedOn(new java.util.Date());
		
		List<String> errors = validate(invoice);
		
		if(!errors.isEmpty()){
			resp.setSuccess(false);			
			resp.setMessages(errors);
			return resp;
		
		}		
		invoiceService.saveInvoice(invoice);
		return resp;
	}
	
	
	
	@RequestMapping(value = "/delete/{id}", method = RequestMethod.PUT)	
	public @ResponseBody CustomGenericResponse delete(@PathVariable("id") int id){
		CustomGenericResponse resp = new CustomGenericResponse();
		try {
			Invoice invoice = invoiceService.findInvoiceByPrimaryKey(id);
			
			
			List<String> errors = validate(invoice);
			Set<Item> items = invoice.getItems();	
			if(items != null && items.size() !=0){
				errors.add("Posee registros asociados, No puede eliminarla");
				resp.setSuccess(true);
				resp.setMessage("Error");
				return resp;
			}
			
			invoiceService.deleteInvoice(invoice);
			resp.setSuccess(true);
			resp.setMessage("Success");
		} catch (Exception e) {
			resp.setSuccess(true);
			resp.setMessage("Error");
		}		
		return resp;
		
	}
	
	/*metodos para detalle*/
	
	@RequestMapping(value = "/itlist/{id}", method = RequestMethod.GET)
	public @ResponseBody Page<Item> listUsers(@PathVariable("id") int id,
			@RequestParam(value = "page", required = false, defaultValue = "1") int page,
		      @RequestParam(value = "max", required = false, defaultValue = "20") int max){
		
		Invoice inv = invoiceService.findInvoiceByPrimaryKey(id);
		List<Item> lst = new ArrayList<Item>();
		Set<Item> items = new HashSet<Item>();
		if(inv != null){				
			items= inv.getItems();			
		}
		
		
		for (Item item : items) {
			lst.add(item);
		}
		Page<Item> pg = new Page<Item>();
		pg.setMax(max);
		pg.setPage(page);
		pg.setRows(lst);
		return pg;
	}
	
	
	@RequestMapping(value = "/saveItem", method = RequestMethod.PUT)	
	public @ResponseBody CustomGenericResponse  saveItem(
			@RequestBody Item item){
		CustomGenericResponse resp = new CustomGenericResponse();		
		Invoice inv = invoiceService.findInvoiceByPrimaryKey(item.getIntInvoiceId());
		item.setInvoice(inv);
		
		Product product = productService.findProductByPrimaryKey(item.getIntProductId());
		
		item.setProduct(product);
		
		item.setCreatedBy(getUserName());
		item.setCreatedOn(new java.util.Date());
		
		
		List<String> errors = validate(item);		
		if(!errors.isEmpty()){
			resp.setSuccess(false);			
			resp.setMessages(errors);
			return resp;
		}		
		try {
			itemService.saveItem(item);			
		} catch (Exception e) {
			errors.add("Error al agregar Factura "+e.getMessage() );
		}
		
		return resp;
	}
	

	
	@RequestMapping(value = "/updateItem/", method = RequestMethod.PUT)
	public @ResponseBody CustomGenericResponse  updateItem(@RequestBody Item item){
		CustomGenericResponse resp = new CustomGenericResponse();
		List<String> errors = validate(item);
		
		if(!errors.isEmpty()){
			resp.setSuccess(false);			
			resp.setMessages(errors);
			return resp;
		
		}
		item.setModifiedBy(getUserName());
		item.setModifiedOn(new java.util.Date());
		itemService.saveItem(item);
		return resp;
	}
	
	
	
	@RequestMapping(value = "/deleteItem/{id}", method = RequestMethod.PUT)	
	public @ResponseBody CustomGenericResponse deleteItem(@PathVariable("id") int id){
		CustomGenericResponse resp = new CustomGenericResponse();
		try {
			Item item = itemService.findItemByPrimaryKey(id);
			itemService.deleteItem(item);
			resp.setSuccess(true);
			resp.setMessage("Success");
		} catch (Exception e) {
			resp.setSuccess(true);
			resp.setMessage("Error");
		}		
		return resp;		
	}
	
	@InitBinder
    public void initBinder(WebDataBinder binder, HttpSession session, HttpServletRequest request) {
		
				
    }
	
	
	
	private void setProductList(HttpSession session){
		Set<Product> products = productService.loadProducts();
		//value:"1:val1;2:val2"
		String str = "";
		for (Product product : products) {
			str += product.getId() +":" + product.getName() + ";";			
		}		
		str = str.substring(0, str.length()-1);
		session.setAttribute("productComboList", str);
		
	}
	
	
	public String getUserName(){
		Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		if(obj instanceof UserDetails){
			return ((UserDetails)obj).getUsername();
		}
		return "";
	}
	
	
	/*-- ------------------------------------------------- --*/
	
	

	private List<String> validate(Invoice invoice) {
		List<String> errors = new ArrayList<String>();
		Set<ConstraintViolation<Invoice>> violations = validator
				.validate(invoice);
		for (ConstraintViolation<Invoice> violation : violations)
			errors.add(violation.getMessage());
		return errors;
	}
	
	
	
	private List<String> validate(Item item) {
		List<String> errors = new ArrayList<String>();
		Set<ConstraintViolation<Item>> violations = validator
				.validate(item);
		for (ConstraintViolation<Item> violation : violations)
			errors.add(violation.getMessage());
		return errors;
	}
	

}// class